/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
    ArkFile,
    AstTreeUtils,
    ts,
} from 'arkanalyzer';
import { Rule } from '../../Index';
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from '../BaseChecker';
import { Defects } from '../../Index';
import {
    FileMatcher,
    MatcherCallback,
    MatcherTypes,
} from '../../Index';
import { RuleListUtil } from "../../utils/common/DefectsList";
import { IssueReport } from '../../model/Defects';
const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'NoRestrictedSyntaxCheck');

interface Violation {
    line: number;
    column: number;
    message: string;
}

interface RestrictedRule {
    selector: string;
    message: string;
}

interface ParsedRule {
    type: string;
    attributes: AttributeCondition[];
    parent: ParsedRule | null;
    message: string;
}

interface AttributeCondition {
    path: string[];
    operator: string;
    value: any;
}

interface MessageInfo {
    line: number;
    character: number;
    endCol: number;
    message: string
}

type Options = Array<string | { selector: string; message?: string }>;

export class NoRestrictedSyntaxCheck implements BaseChecker {
    public issues: IssueReport[] = [];
    public rule: Rule;
    public defects: Defects[] = [];
    private defaultOptions: Options = [];
    public metaData: BaseMetaData = {
        severity: 2,
        ruleDocPath: 'docs/no-restricted-syntax-check.md',
        description: 'Disallow specified syntax',
    };

    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    public registerMatchers(): MatcherCallback[] {
        const matchFileCb: MatcherCallback = {
            matcher: this.fileMatcher,
            callback: this.check
        }
        return [matchFileCb];
    }

    public check = (targetField: ArkFile) => {
        this.defaultOptions = this.getDefaultOption();
        if (this.defaultOptions.length > 0) { //不配置option不做检测
            const severity = this.rule.alert ?? this.metaData.severity;
            const filePath = targetField.getFilePath();
            let code = targetField.getCode();
            const myInvalidPositions = this.checkRestrictedSyntax(targetField.getName(), code, this.defaultOptions);
            myInvalidPositions.forEach(pos => {
                this.addIssueReport(filePath, pos, severity);
            });
        }
    }

    private getDefaultOption(): Options {
        let tmpOption: Options = [];
        if (this.rule && this.rule.option) {
            for (let index = 0; index < this.rule.option.length; index++) {
                const element = this.rule.option[index];
                if (typeof element === 'string') {
                    tmpOption.push(element);
                } else {
                    const elem = element as { selector: string; message?: string };
                    tmpOption.push({ selector: elem.selector, message: elem.message });
                }
            }
        }
        return tmpOption;
    }

    private addIssueReport(filePath: string, pos: MessageInfo, severity: number) {
        let defect = new Defects(pos.line, pos.character, pos.endCol, pos.message, severity, this.rule.ruleId,
            filePath, this.metaData.ruleDocPath, true, false, false);
        this.issues.push(new IssueReport(defect, undefined));
        RuleListUtil.push(defect);
    }

    private checkRestrictedSyntax(fileName: string, code: string, options: Array<string | { selector: string; message?: string }>): MessageInfo[] {
        const errors: MessageInfo[] = [];
        const rules = this.normalizeOptions(options);
        const parsedRules = rules.map(rule => this.parseRule(rule));
        const sourceFile = AstTreeUtils.getASTNode(fileName, code);

        const nodeStack: ts.Node[] = [];

        function visit(node: ts.Node) {
            nodeStack.push(node);
            // 特殊处理 * ~ * 规则
            if (ts.isArrayLiteralExpression(node)) {
                const elements = node.elements;
                // 检查数组中的相邻元素
                for (let i = 0; i < elements.length - 1; i++) {
                    const currentElement = elements[i];
                    const nextElement = elements[i + 1];

                    // 检查是否存在相邻的兄弟节点
                    if (currentElement && nextElement) {
                        const { line, character } = sourceFile.getLineAndCharacterOfPosition(nextElement.getStart());
                        // 检查是否有规则匹配 * ~ *
                        const matchingRule = parsedRules.find(rule =>
                            rule.type === 'BinaryExpression' &&
                            rule.attributes.some(attr =>
                                attr.path[0] === 'operatorToken' &&
                                attr.path[1] === 'kind' &&
                                attr.value === ts.SyntaxKind.TildeToken
                            )
                        );

                        if (matchingRule) {
                            errors.push({
                                line: line + 1,
                                character: character + 1,
                                endCol: character + node.getText().length + 1,
                                message: matchingRule.message
                            });
                        }
                    }
                }
            }

            for (const rule of parsedRules) {
                let nodeFlag = rule.type === 'Node' && rule.attributes.some(attr => attr.path[0] === 'optional' && attr.value === true); //[optional=true]
                if (nodeFlag) {
                    // 检查当前节点是否是可选链
                    if ((ts.isPropertyAccessChain(node) || ts.isElementAccessChain(node) || ts.isCallChain(node))
                        && node.questionDotToken) {
                        // 查找变量声明节点
                        let parent = node.parent;
                        while (parent !== null && parent !== undefined && !ts.isVariableDeclaration(parent)) {
                            parent = parent.parent;
                        }

                        // 安全获取起始位置
                        const startPos = (parent && ts.isVariableDeclaration(parent) && parent.initializer)
                            ? parent.initializer.getStart()
                            : node.getStart();
                        const { line, character } = sourceFile.getLineAndCharacterOfPosition(startPos);

                        // 添加错误
                        errors.push({
                            line: line + 1,
                            character: character + 1,
                            endCol: character + node.getText().length + 1,
                            message: rule.message
                        });
                    }
                } else if (matchRule(node, rule, nodeStack)) {
                    // 新增：排除 catch 子句中的变量声明
                    if (rule.type === 'VariableDeclaration' &&
                        nodeStack.some(n => ts.isCatchClause(n.parent))) {
                        continue;
                    }

                    // 关键优化：处理 VariableDeclaration 的父节点位置
                    let targetNode = node;
                    if (ts.isVariableDeclaration(node)) {
                        // 获取 VariableDeclarationList 父节点
                        const parent = node.parent;
                        if (ts.isVariableDeclarationList(parent)) {
                            targetNode = parent;
                        }
                    }

                    let startPos = targetNode.getStart();
                    if (rule.type === 'ClassDeclaration' && ts.isClassDeclaration(node) && node.name) {
                        // 获取完整的节点文本
                        const fullText = sourceFile.getFullText();
                        // 从节点开始位置查找 'class' 关键字
                        const classKeywordPos = fullText.indexOf('class', node.getStart());
                        if (classKeywordPos !== -1) {
                            startPos = classKeywordPos;
                        }
                    }

                    const { line, character } = sourceFile.getLineAndCharacterOfPosition(startPos);
                    errors.push({
                        line: line + 1,
                        character: character + 1,
                        endCol: character + node.getText().length + 1,
                        message: rule.message
                    });
                }
            }

            ts.forEachChild(node, visit);
            nodeStack.pop();
        }

        function checkAttribute(node: ts.Node, condition: AttributeCondition): boolean {
            let value: any = node;
            // 特殊处理 CallExpression 的参数长度检查
            if (ts.isCallExpression(node) && condition.path[0] === 'arguments') {
                if (condition.path[1] === 'length') {
                    value = node.arguments.length;
                    const expectedValue = condition.value;
                    
                    switch (condition.operator) {
                        case '!=': return value !== expectedValue;
                        case '==': return value === expectedValue;
                        case '>': return value > expectedValue;
                        case '>=': return value >= expectedValue;
                        case '<': return value < expectedValue;
                        case '<=': return value <= expectedValue;
                        default: return false;
                    }
                }
            } else if (ts.isCallExpression(node) && condition.path[0] === 'expression') {
                if (condition.path[1] === 'text') {
                    return node.expression.getText() === condition.value;
                }
            }

            // 新增：处理 BreakStatement 的 label 属性
            if (ts.isBreakStatement(node) && condition.path[0] === 'label') {
                return node.label !== undefined;  // 仅当存在标签时返回 true
            }

            // 特殊处理正则表达式的标志
            if (ts.isRegularExpressionLiteral(node) && condition.operator === '~=') {
                const nodeText = node.getText();
                return condition.value.test(nodeText);
            }

            if (condition.path[0] === 'operator' && ts.isBinaryExpression(node)) {
                if (node.operatorToken.kind === ts.SyntaxKind.InKeyword) {
                    value = 'in';
                } else {
                    value = node.operatorToken.getText().trim();
                }
            } else if (ts.isIdentifier(node) && condition.path[0] === 'name') {
                value = node.text;
            } else {
                for (const prop of condition.path) {
                    if (!(prop in value)) return false;
                    value = value[prop];
                }
            }

            const expectedValue = typeof condition.value === 'string'
                ? condition.value.replace(/^['"]|['"]$/g, '').trim()
                : condition.value;
            const actualValue = typeof value === 'string'
                ? value.trim()
                : value;

            return actualValue === expectedValue;
        }

        function matchRule(node: ts.Node, rule: ParsedRule, stack: ts.Node[]): boolean {
            // 特殊处理 ChainExpression
            if (rule.type === 'ChainExpression') {
                const isChain = ts.isPropertyAccessChain(node) || ts.isElementAccessChain(node) || ts.isCallChain(node);
                if (!isChain) return false;

                // 检查父节点是否是 ChainExpression 类型
                const parent = node.parent;
                const parentIsChain = parent && (
                    ts.isPropertyAccessChain(parent) ||
                    ts.isElementAccessChain(parent) ||
                    ts.isCallChain(parent)
                );

                // 仅当父节点不是 ChainExpression 时匹配
                return !parentIsChain;
            }

            // 特殊处理纯属性选择器
            if (rule.type === 'Node') {
                // 处理 :nth-child(n) 选择器
                if (rule.attributes.some(attr => attr.path[0] === 'index')) {
                    const sourceFile = node.getSourceFile();
                    const statements = sourceFile.statements;
                    const targetIndex = rule.attributes.find(attr => attr.path[0] === 'index')?.value || 0;
                    return statements[targetIndex] === node;
                }

                // 检查是否是可选链表达式
                if (rule.attributes.some(attr =>
                    attr.path[0] === 'optional' &&
                    attr.value === true
                )) {
                    return ts.isPropertyAccessChain(node) ||
                        ts.isElementAccessChain(node) ||
                        ts.isCallChain(node);
                }
                return false;
            }

            let currentRule: ParsedRule | null = rule;
            let currentDepth = stack.length - 1;

            if (rule.type === 'FunctionDeclaration') {
                return matchRuleForFunctionDeclaration(node, rule, stack);
            } else {
                while (currentRule && currentDepth >= 0) {
                    const currentNode = stack[currentDepth];
                    const nodeTypeName = ts.SyntaxKind[currentNode.kind];
                    if (nodeTypeName !== currentRule.type) {
                        return false;
                    }

                    if (!currentRule.attributes.every(attr => checkAttribute(currentNode, attr))) {
                        return false;
                    }

                    currentRule = currentRule.parent;
                    currentDepth--;
                }
                return currentRule === null;
            }
        }

        function matchRuleForFunctionDeclaration(node: ts.Node, rule: ParsedRule, stack: ts.Node[]): boolean {
            let currentRule: ParsedRule | null = rule;
            let currentDepth = stack.length - 1;

            // 首先找到最深层的节点（规则中的第一个部分）
            let firstRule: ParsedRule = currentRule;
            while (firstRule.parent) {
                firstRule = firstRule.parent;
            }

            // 从规则的第一个部分开始匹配
            let currentNode = node;
            let ruleToCheck: ParsedRule | null = firstRule;

            // 检查节点类型和属性
            if (ruleToCheck) {
                // 检查节点类型是否匹配
                if (ts.SyntaxKind[currentNode.kind] !== ruleToCheck.type) {
                    return false;
                }

                // 特殊处理函数声明的参数长度检查
                if (ts.isFunctionDeclaration(currentNode) && ruleToCheck.attributes.length > 0) {
                    const attr = ruleToCheck.attributes[0];
                    if (attr.path[0] === 'params' && attr.path[1] === 'length') {
                        const paramsLength = currentNode.parameters.length;
                        const value = parseInt(attr.value);

                        switch (attr.operator) {
                            case '>':
                                return paramsLength > value;
                            case '>=':
                                return paramsLength >= value;
                            case '<':
                                return paramsLength < value;
                            case '<=':
                                return paramsLength <= value;
                            case '=':
                            case '==':
                                return paramsLength === value;
                            case '!=':
                                return paramsLength !== value;
                        }
                    }
                }

                // 检查其他属性条件
                if (!ruleToCheck.attributes.every(attr => checkAttribute(currentNode, attr))) {
                    return false;
                }
            }

            return true;
        }

        ts.forEachChild(sourceFile, visit);
        return errors;
    }

    // 在 NoRestrictedSyntaxCheck 类中添加映射表
    private eslintToTsNodeMap: { [eslintType: string]: string } = {
        'ArrowFunctionExpression': 'ArrowFunction',
        'BlockStatement': 'Block',
        'VariableDeclaration': 'VariableDeclaration',
        'FunctionExpression': 'FunctionExpression',
        'WithStatement': 'WithStatement',
        'BinaryExpression': 'BinaryExpression',
        'Identifier': 'Identifier',
        'VariableStatement': 'VariableStatement',
        'CatchClause': 'CatchClause',
        'Property': 'PropertyAssignment',
        'Literal': 'StringLiteral',
        'ChainExpression': 'ChainExpression',  // 新增映射
        'BreakStatement': 'BreakStatement'  // 新增映射
    };

    // Helper functions
    private normalizeOptions(
        options: Array<string | { selector: string; message?: string }>
    ): RestrictedRule[] {
        return options.map(opt => ({
            selector: typeof opt === 'string' ? opt : opt.selector,
            message: typeof opt === 'string' ? `Using '${opt}' is not allowed.` :
                (opt.message || `Using '${opt.selector}' is not allowed.`)
        }));
    }

    private parseRule(rule: RestrictedRule): ParsedRule {
        // 特殊处理通配符语法
        if (rule.selector === '* ~ *') {
            return {
                type: 'BinaryExpression',
                attributes: [{
                    path: ['operatorToken', 'kind'],
                    operator: '=',
                    value: ts.SyntaxKind.TildeToken
                }],
                parent: null,
                message: rule.message
            };
        }

        // 特殊处理 CallExpression 的参数长度检查
        if (rule.selector.includes('CallExpression') && rule.selector.includes('arguments.length')) {
            const calleeName = rule.selector.match(/callee\.name='([^']+)'/)?.[1];
            const argsCondition = rule.selector.match(/arguments\.length([!<>=]+)(\d+)/);
            
            if (calleeName && argsCondition) {
                return {
                    type: 'CallExpression',
                    attributes: [
                        {
                            path: ['expression', 'text'],
                            operator: '=',
                            value: calleeName
                        },
                        {
                            path: ['arguments', 'length'],
                            operator: argsCondition[1],
                            value: parseInt(argsCondition[2])
                        }
                    ],
                    parent: null,
                    message: rule.message
                };
            }
        }

        // 使用正则表达式分割选择器，排除属性条件中的 '>'
        const parts = rule.selector.split(/(?![^[]*\])\s*>\s*/) as string[];
        let parent: ParsedRule | null = null;

        // 改进的选择器解析逻辑
        for (let i = 0; i < parts.length; i++) {
            const [type, attributes] = this.parseSelectorPart(parts[i]);

            // 特殊处理 ChainExpression
            if (type === 'ChainExpression') {
                parent = {
                    type: type,
                    attributes: attributes,
                    parent: parent,
                    message: rule.message
                };
                continue;
            }

            // 特殊处理纯属性选择器返回的 Node 类型
            if (type === 'Node') {
                parent = {
                    type: type,
                    attributes: attributes,
                    parent: parent,
                    message: rule.message
                };
                continue;
            }

            // 使用映射表获取 TypeScript 类型
            const tsType = this.eslintToTsNodeMap[type] || type;

            // 确保类型名称与 TypeScript AST 节点类型完全匹配
            const validType = Object.values(ts.SyntaxKind)
                .find(kind => typeof kind === 'string' && kind === tsType);

            if (!validType) {
                throw new Error(`Invalid node type: ${type}`);
            }

            parent = {
                type: tsType,
                attributes: attributes,
                parent: parent,
                message: rule.message
            };
        }

        return parent!;
    }

    private parseSelectorPart(selector: string): [string, AttributeCondition[]] {
        // 特殊处理通配符语法
        if (selector === '* ~ *') {
            return ['BinaryExpression', [{
                path: ['operatorToken', 'kind'],
                operator: '=',
                value: ts.SyntaxKind.TildeToken
            }]];
        }

        // 处理 :nth-child(n) 选择器
        if (selector.startsWith(':nth-child')) {
            return ['Node', [{
                path: ['index'],
                operator: '=',
                value: parseInt(selector.match(/\((\d+)\)/)?.[1] || '1') - 1
            }]];
        }

        // 处理纯属性条件的选择器
        if (selector.startsWith('[') && selector.endsWith(']')) {
            const attrContent = selector.slice(1, -1);
            const [path, value] = attrContent.split('=').map(s => s.trim());
            return ['Node', [{
                path: path.split('.'),
                operator: '=',
                value: value === 'true' ? true : value === 'false' ? false : value
            }]];
        }

        // 修改正则表达式以更准确地匹配选择器部分
        const selectorMatch = selector.match(/^([^[]+)(?:\[(.*)\])?/);
        if (!selectorMatch) throw new Error(`Invalid selector: ${selector}`);

        let [_, typePart, attrStr] = selectorMatch;
        const attributes: AttributeCondition[] = [];
        typePart = typePart.trim();

        // 处理 Literal.key 的特殊情况
        if (typePart === 'Literal.key') {
            return [
                'StringLiteral',  // 映射到 TypeScript 的 StringLiteral 类型
                []
            ];
        } else if (typePart === 'Property') {  // 映射 ESLint 类型到 TS 类型名称
            typePart = 'PropertyAssignment';
        } else if (typePart === 'Literal') {
            typePart = 'RegularExpressionLiteral';
        }

        if (this.eslintToTsNodeMap[typePart]) {
            typePart = this.eslintToTsNodeMap[typePart];
        }

        if (attrStr) {
            // 新增：处理仅有属性名的情况（例如 [label]）
            if (/^[\w.]+$/.test(attrStr)) {
                attributes.push({
                    path: attrStr.split('.'),
                    operator: 'exists',
                    value: true
                });
            } else {
                // 处理正则表达式标志的检查
                const regexMatch = attrStr.match(/regex\.flags\s*=\s*\/(.+)\/$/);
                if (regexMatch) {
                    attributes.push({
                        path: ['text'],
                        operator: '~=',
                        value: new RegExp(`/${regexMatch[1]}$`)
                    });
                } else {
                    // 修改属性匹配正则表达式，更准确地处理引号
                    const attrRegex = /([\w.]+)\s*(=|!=|>=|<=|>|<|~=|in)\s*(?:'([^']*)'|"([^"]*)"|(\S+))/g;
                    let attrMatch: RegExpExecArray | null;

                    while ((attrMatch = attrRegex.exec(attrStr)) !== null) {
                        const [_, path, op, value1, value2, value3] = attrMatch;
                        // 使用第一个非undefined的值
                        const value = value1 ?? value2 ?? value3;

                        attributes.push({
                            path: path.split('.'),
                            operator: op, //op === '~=' ? 'regex' : op,
                            value: this.parseValue(value, op)
                        });
                    }
                }
            }
        }

        return [typePart, attributes];
    }

    // 增强的值解析方法
    private parseValue(rawValue: string, operator: string): any {
        // 处理正则表达式
        if (operator === '~=') {
            return new RegExp(rawValue);
        }

        // 处理布尔值
        if (rawValue === 'true') return true;
        if (rawValue === 'false') return false;

        // 处理null/undefined
        if (rawValue === 'null') return null;
        if (rawValue === 'undefined') return undefined;

        // 处理数字
        const numericValue = Number(rawValue);
        if (!isNaN(numericValue)) return numericValue;

        // 默认返回字符串
        return rawValue;
    }
}